const RowTemplate = require('./row-template');
const ColumnTemplate = require('./column-template');

/**
 * 模板sheet，静态内容预渲染，只允许顺序添加行；动态内容从静态内容之后开始添加
 * @property {RowTemplate[]} rows
 * @property {ColumnTemplate[]} cols
 * @property {string} options.id
 * @property {string} options.name
 * @property {string} options.state
 */
class WorksheetTemplate {
  /**
   * @param {Object} options
   * @param {string} options.id
   * @param {string} options.name
   * @param {string} options.state
   * @param {number} options.start
   */
  constructor(options) {
    this.rows = [];
    this.cols = [];
    this.id = options.id;
    this.name = options.name;
    this.state = options.state || 'visible';
    // 列排头
    this.headers = [];
    // </sheetData> 与 </worksheet> 之间的xml内容
    this.xmlAfterSheetData = [];
    // 非模板的静态行的值，固定的，而非动态渲染
    this.staticRowValues = [];
    // 从第几行开始是模板行
    this._start = typeof options.start === 'number' && options.start >= 1 ? options.start : 1;
  }

  preRender(ctx) {
    this.cols.forEach(col => col.preRender(ctx));
    this.rows.forEach(row => row.preRender(ctx));
    this.rows.forEach(row => row.clear());
  }

  renderHeader(ctx) {
    const { xmlStream } = ctx;
    xmlStream.writeXml(this.xmlHeader);
    xmlStream.writeXml('<cols>');
    this.cols.forEach(col => col.render(ctx, xmlStream));
    xmlStream.writeXml('</cols>');

    xmlStream.writeXml('<sheetData>');

    // 渲染列排头之前的行
    for (let i = 0; i < this.start - 1; i++) {
      this.render({
        ...ctx,
        rowNo: i + 1,
        data: this.staticRowValues[i]
      });
    }
    // 渲染列排头
    this.render({
      ...ctx,
      rowNo: this.start - 1,
      data: this.headers
    });
  }

  /**
   * @param {Object} ctx
   * @param {number} ctx.rowNo
   * @param {{writeXml: (xml: string) => void}} ctx.xmlStream
   * @param {any} ctx.data
   * @param value
   */
  render(ctx) {
    const { rowNo } = ctx;
    const row = this.getRowForRender(rowNo);
    const renderCount = 1;
    row.render(ctx);
    return renderCount;
  }

  renderTail(ctx) {
    const { xmlStream } = ctx;
    xmlStream.writeXml('</sheetData>');

    // todo: hyperlinks等
    this.xmlAfterSheetData.forEach(xml => xmlStream.writeXml(xml));

    xmlStream.writeXml('</worksheet>');
  }

  addRow(count = 1) {
    while (count--) {
      const rowNo = this.rows.length + 1;
      const row = new RowTemplate(this, rowNo);
      this.rows.push(row);
    }
  }

  getRow(rowNo) {
    if (rowNo > this.rows.length) {
      this.addRow(rowNo - this.rows.length);
    }
    return this.rows[rowNo - 1];
  }

  getRowForRender(rowNo) {
    const row = this.rows[rowNo - 1];
    if (!row) {
      throw new Error(`超出模板行上限，当前渲染${rowNo}行，总共包含${this.rows.length}行`);
    }
    return row;
  }

  getCell(rowNo, colNo) {
    const row = this.getRow(rowNo);
    return row.getCell(colNo);
  }

  getCol(colNo) {
    const { cols } = this;
    const len = cols.length;
    if (colNo <= len) {
      return cols[colNo - 1];
    } else {
      for (let i = len; i < colNo; i++) {
        cols.push(new ColumnTemplate(this, i + 1));
      }
      return cols[colNo - 1];
    }
  }

  set columns(cols) {
    cols.forEach((col, index) => {
      const column = this.cols[index] || new ColumnTemplate(this, index + 1);
      // push要在defn之前
      this.cols.push(column);
      column.defn = col;
      this.start = col.rowNumber + 1;
      this.headers.push(col.header);
    });
  }

  get lastRow() {
    return this.rows[this.rows.length - 1];
  }

  addDrawing(rid) {
    this.xmlAfterSheetData.push(`<drawing r:id="${rid}"/>`);
  }

  addMergeCells(merges) {
    let mergeCells = `<mergeCells count="${merges.length}">`;
    merges.forEach(range => {
      mergeCells += `<mergeCell ref="${range}"/>`;
    });
    this.xmlAfterSheetData.push(mergeCells + '</mergeCells>');
  }

  get start() {
    return this._start;
  }

  set start(val) {
    this._start = Math.max(val, this._start);
  }
}

WorksheetTemplate.prototype.xmlHeader = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="x14ac" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac">';

module.exports = WorksheetTemplate;
